package com.dscs.aspect;

import com.alibaba.fastjson.JSON;
import com.dscs.annotation.PermissionAnnotation;
import com.dscs.domain.Permission;
import com.dscs.service.IUserService;
import com.dscs.util.Msg;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author 叶雪娟
 * @date 2019/7/18
 * 创建切面类
 **/
@Aspect
@Component
public class ServiceAdvice {

    @Autowired
    private IUserService ius;

    /**
     * 用户权限拦截
     * 在用户访问Controller类的方法前判断用户是否有该方法访问权限
     * 1.前端输入用户UserId
     * 2.
     */
    @Before("execution(* com.dscs.controller.*.*(..))")
    public boolean beforeFunction(JoinPoint joinPoint) throws IOException {
        System.out.println("这是前置通知。");
        //获取request和response
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        Boolean validate = false;
        if (isValidate(joinPoint)) {
            validate = validateUserPermission(request);
        } else {
            validate = true;
        }
        if (validate) {
            return true;
        } else {//没有该请求的访问权限权限
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json");
            response.setStatus(403);
            Msg m = new Msg();
            m.setMsg("该用户没有访问权限。");
            m.setStatus(false);
            PrintWriter writer = response.getWriter();
            String msg = JSON.toJSONString(m);
            writer.print(msg);
            writer.close();
        }
        return validate;


    }


    /**
     * isValidate 方法
     * 判断是否需要进行权限校验
     */
    private Boolean isValidate(JoinPoint joinPoint) {
        //通知的签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //代理的是哪一个方法
        System.out.println(signature.getName());
        //AOP代理类的名字
        System.out.println(signature.getDeclaringTypeName());
        Method method = signature.getMethod();
        PermissionAnnotation annotation = signature.getMethod().getAnnotation(PermissionAnnotation.class);
        if (!StringUtils.isEmpty(annotation)) {//控制类方法上使用自定义注解的值是否为空，若不为空
            return annotation.value();
        } else {
            PermissionAnnotation classAnotation = method.getDeclaringClass().getAnnotation(PermissionAnnotation.class);
            if (!StringUtils.isEmpty(classAnotation)) {//控制类上使用自定义注解的值是否为空，若不为空
                return classAnotation.value();
            }
        }
        return false;
    }

    /**
     * validateUserPermission 方法
     * 判断用户是否有相应方法的访问权限
     */
    private Boolean validateUserPermission(HttpServletRequest request) {
        boolean result = false;
        System.out.println("从获取RequestAttributes中获取HttpServletRequest的信息 ");
        String uri = request.getRequestURI();
        if (uri.contains("user")){
            return true;
        }
        System.out.println(" uri : " + uri);
        String method = request.getMethod();
        System.out.println(" method : " + method);
        String userId = request.getParameter("userId");
        long id = Integer.valueOf(userId);
        List<Permission> permissionList = ius.queryUserPermission(id);
        for (Permission p : permissionList) {
            if (p != null && p.getPath().equals(uri) && p.getMethod().equals(method)) {
                result = true;
            }
        }
        return result;
    }

    @After("execution(* com.dscs.controller.*.*(..))")
    public void afterFunction() {
        System.out.println("这是后置通知。");
    }

    @AfterReturning(pointcut = "execution(* com.dscs.controller.*.*(..))", returning = "object")
    public void afterReturning(Object object) {
        System.out.println("返回结果后： " + object);
    }

}
